home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: gdevpx.c,v 1.4 2000/09/19 19:00:22 lpd Exp $ */
- /* H-P PCL XL driver */
- #include "math_.h"
- #include "memory_.h"
- #include "string_.h"
- #include "gx.h"
- #include "gserrors.h"
- #include "gsccolor.h"
- #include "gsdcolor.h"
- #include "gxcspace.h" /* for color mapping for images */
- #include "gxdevice.h"
- #include "gxpath.h"
- #include "gdevvec.h"
- #include "strimpl.h"
- #include "srlx.h"
- #include "gdevpxat.h"
- #include "gdevpxen.h"
- #include "gdevpxop.h"
- #include "gdevpxut.h"
-
- /* ---------------- Device definition ---------------- */
-
- /* Define the default resolution. */
- #ifndef X_DPI
- # define X_DPI 600
- #endif
- #ifndef Y_DPI
- # define Y_DPI 600
- #endif
-
- /* Structure definition */
- #define NUM_POINTS 40 /* must be >= 3 and <= 255 */
- typedef enum {
- POINTS_NONE,
- POINTS_LINES,
- POINTS_CURVES
- } point_type_t;
- typedef struct gx_device_pclxl_s {
- gx_device_vector_common;
- /* Additional state information */
- pxeMediaSize_t media_size;
- gx_path_type_t fill_rule; /* ...winding_number or ...even_odd */
- gx_path_type_t clip_rule; /* ditto */
- pxeColorSpace_t color_space;
- struct pal_ {
- int size; /* # of bytes */
- byte data[256 * 3]; /* up to 8-bit samples */
- } palette;
- struct pts_ { /* buffer for accumulating path points */
- gs_int_point current; /* current point as of start of data */
- point_type_t type;
- int count;
- gs_int_point data[NUM_POINTS];
- } points;
- struct ch_ { /* cache for downloaded characters */
- #define MAX_CACHED_CHARS 400
- #define MAX_CHAR_DATA 500000
- #define MAX_CHAR_SIZE 5000
- #define CHAR_HASH_FACTOR 247
- ushort table[MAX_CACHED_CHARS * 3 / 2];
- struct cd_ {
- gs_id id; /* key */
- uint size;
- } data[MAX_CACHED_CHARS];
- int next_in; /* next data element to fill in */
- int next_out; /* next data element to discard */
- int count; /* of occupied data elements */
- ulong used;
- } chars;
- bool font_set;
- } gx_device_pclxl;
-
- gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
- "gx_device_pclxl",
- device_pclxl_enum_ptrs, device_pclxl_reloc_ptrs,
- gx_device_finalize, st_device_vector);
-
- #define pclxl_device_body(dname, depth)\
- std_device_dci_type_body(gx_device_pclxl, 0, dname, &st_device_pclxl,\
- DEFAULT_WIDTH_10THS * X_DPI / 10,\
- DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
- X_DPI, Y_DPI,\
- (depth > 8 ? 3 : 1), depth,\
- (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
- (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
-
- /* Driver procedures */
- private dev_proc_open_device(pclxl_open_device);
- private dev_proc_output_page(pclxl_output_page);
- private dev_proc_close_device(pclxl_close_device);
- private dev_proc_copy_mono(pclxl_copy_mono);
- private dev_proc_copy_color(pclxl_copy_color);
- private dev_proc_fill_mask(pclxl_fill_mask);
-
- /*private dev_proc_draw_thin_line(pclxl_draw_thin_line); */
- private dev_proc_begin_image(pclxl_begin_image);
- private dev_proc_strip_copy_rop(pclxl_strip_copy_rop);
-
- #define pclxl_device_procs(map_rgb_color, map_color_rgb)\
- {\
- pclxl_open_device,\
- NULL, /* get_initial_matrix */\
- NULL, /* sync_output */\
- pclxl_output_page,\
- pclxl_close_device,\
- map_rgb_color, /* differs */\
- map_color_rgb, /* differs */\
- gdev_vector_fill_rectangle,\
- NULL, /* tile_rectangle */\
- pclxl_copy_mono,\
- pclxl_copy_color,\
- NULL, /* draw_line */\
- NULL, /* get_bits */\
- gdev_vector_get_params,\
- gdev_vector_put_params,\
- NULL, /* map_cmyk_color */\
- NULL, /* get_xfont_procs */\
- NULL, /* get_xfont_device */\
- NULL, /* map_rgb_alpha_color */\
- gx_page_device_get_page_device,\
- NULL, /* get_alpha_bits */\
- NULL, /* copy_alpha */\
- NULL, /* get_band */\
- NULL, /* copy_rop */\
- gdev_vector_fill_path,\
- gdev_vector_stroke_path,\
- pclxl_fill_mask,\
- gdev_vector_fill_trapezoid,\
- gdev_vector_fill_parallelogram,\
- gdev_vector_fill_triangle,\
- NULL /****** WRONG ******/, /* draw_thin_line */\
- pclxl_begin_image,\
- NULL, /* image_data */\
- NULL, /* end_image */\
- NULL, /* strip_tile_rectangle */\
- pclxl_strip_copy_rop\
- }
-
- const gx_device_pclxl gs_pxlmono_device = {
- pclxl_device_body("pxlmono", 8),
- pclxl_device_procs(gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb)
- };
-
- const gx_device_pclxl gs_pxlcolor_device = {
- pclxl_device_body("pxlcolor", 24),
- pclxl_device_procs(gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb)
- };
-
- /* ---------------- Other utilities ---------------- */
-
- inline private stream *
- pclxl_stream(gx_device_pclxl *xdev)
- {
- return gdev_vector_stream((gx_device_vector *)xdev);
- }
-
- /* Initialize for a page. */
- private void
- pclxl_page_init(gx_device_pclxl * xdev)
- {
- gdev_vector_init((gx_device_vector *)xdev);
- xdev->in_page = false;
- xdev->fill_rule = gx_path_type_winding_number;
- xdev->clip_rule = gx_path_type_winding_number;
- xdev->color_space = eNoColorSpace;
- xdev->palette.size = 0;
- xdev->font_set = false;
- }
-
- /* Test whether a RGB color is actually a gray shade. */
- #define RGB_IS_GRAY(ci) ((ci) >> 8 == ((ci) & 0xffff))
-
- /* Set the color space and (optionally) palette. */
- private void
- pclxl_set_color_space(gx_device_pclxl * xdev, pxeColorSpace_t color_space)
- {
- if (xdev->color_space != color_space) {
- stream *s = pclxl_stream(xdev);
-
- px_put_ub(s, color_space);
- px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
- xdev->color_space = color_space;
- }
- }
- private void
- pclxl_set_color_palette(gx_device_pclxl * xdev, pxeColorSpace_t color_space,
- const byte * palette, uint palette_size)
- {
- if (xdev->color_space != color_space ||
- xdev->palette.size != palette_size ||
- memcmp(xdev->palette.data, palette, palette_size)
- ) {
- stream *s = pclxl_stream(xdev);
- static const byte csp_[] = {
- DA(pxaColorSpace),
- DUB(e8Bit), DA(pxaPaletteDepth),
- pxt_ubyte_array
- };
-
- px_put_ub(s, color_space);
- PX_PUT_LIT(s, csp_);
- px_put_u(s, palette_size);
- px_put_bytes(s, palette, palette_size);
- px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
- xdev->color_space = color_space;
- xdev->palette.size = palette_size;
- memcpy(xdev->palette.data, palette, palette_size);
- }
- }
-
- /* Set a drawing RGB color. */
- private int
- pclxl_set_color(gx_device_pclxl * xdev, const gx_drawing_color * pdc,
- px_attribute_t null_source, px_tag_t op)
- {
- stream *s = pclxl_stream(xdev);
-
- if (gx_dc_is_pure(pdc)) {
- gx_color_index color = gx_dc_pure_color(pdc);
-
- if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
- pclxl_set_color_space(xdev, eGray);
- px_put_uba(s, (byte) color, pxaGrayLevel);
- } else {
- pclxl_set_color_space(xdev, eRGB);
- spputc(s, pxt_ubyte_array);
- px_put_ub(s, 3);
- spputc(s, (byte) (color >> 16));
- spputc(s, (byte) (color >> 8));
- spputc(s, (byte) color);
- px_put_a(s, pxaRGBColor);
- }
- } else if (gx_dc_is_null(pdc))
- px_put_uba(s, 0, null_source);
- else
- return_error(gs_error_rangecheck);
- spputc(s, op);
- return 0;
- }
-
- /* Test whether we can handle a given color space in an image. */
- private bool
- pclxl_can_handle_color_space(const gs_color_space * pcs)
- {
- gs_color_space_index index = gs_color_space_get_index(pcs);
-
- if (index == gs_color_space_index_Indexed) {
- if (pcs->params.indexed.use_proc)
- return false;
- index =
- gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
- }
- return !(index == gs_color_space_index_Separation ||
- index == gs_color_space_index_Pattern);
- }
-
- /* Set brush, pen, and mode for painting a path. */
- private void
- pclxl_set_paints(gx_device_pclxl * xdev, gx_path_type_t type)
- {
- stream *s = pclxl_stream(xdev);
- gx_path_type_t rule = type & gx_path_type_rule;
-
- if (!(type & gx_path_type_fill) &&
- !gx_dc_is_null(&xdev->fill_color)
- ) {
- static const byte nac_[] = {
- DUB(0), DA(pxaNullBrush), pxtSetBrushSource
- };
-
- PX_PUT_LIT(s, nac_);
- color_set_null(&xdev->fill_color);
- if (rule != xdev->fill_rule) {
- px_put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
- eNonZeroWinding));
- px_put_ac(s, pxaFillMode, pxtSetFillMode);
- xdev->fill_rule = rule;
- }
- }
- if (!(type & gx_path_type_stroke) &&
- !gx_dc_is_null(&xdev->stroke_color)
- ) {
- static const byte nac_[] = {
- DUB(0), DA(pxaNullPen), pxtSetPenSource
- };
-
- PX_PUT_LIT(s, nac_);
- color_set_null(&xdev->stroke_color);
- }
- }
-
- /* Set the cursor. */
- private int
- pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
- {
- stream *s = pclxl_stream(xdev);
-
- px_put_ssp(s, x, y);
- px_put_ac(s, pxaPoint, pxtSetCursor);
- return 0;
- }
-
- /* ------ Paths ------ */
-
- /* Flush any buffered path points. */
- private void
- px_put_np(stream * s, int count, pxeDataType_t dtype)
- {
- px_put_uba(s, count, pxaNumberOfPoints);
- px_put_uba(s, dtype, pxaPointType);
- }
- private int
- pclxl_flush_points(gx_device_pclxl * xdev)
- {
- int count = xdev->points.count;
-
- if (count) {
- stream *s = pclxl_stream(xdev);
- px_tag_t op;
- int x = xdev->points.current.x, y = xdev->points.current.y;
- int uor = 0, sor = 0;
- pxeDataType_t data_type;
- int i, di;
- byte diffs[NUM_POINTS * 2];
-
- /*
- * Writing N lines using a point list requires 11 + 4*N or 11 +
- * 2*N bytes, as opposed to 8*N bytes using separate commands;
- * writing N curves requires 11 + 12*N or 11 + 6*N bytes
- * vs. 22*N. So it's always shorter to write curves with a
- * list (except for N = 1 with full-size coordinates, but since
- * the difference is only 1 byte, we don't bother to ever use
- * the non-list form), but lines are shorter only if N >= 3
- * (again, with a 1-byte difference if N = 2 and byte
- * coordinates).
- */
- switch (xdev->points.type) {
- case POINTS_NONE:
- return 0;
- case POINTS_LINES:
- op = pxtLinePath;
- if (count < 3) {
- for (i = 0; i < count; ++i) {
- px_put_ssp(s, xdev->points.data[i].x,
- xdev->points.data[i].y);
- px_put_a(s, pxaEndPoint);
- spputc(s, op);
- }
- goto zap;
- }
- /* See if we can use byte values. */
- for (i = di = 0; i < count; ++i, di += 2) {
- int dx = xdev->points.data[i].x - x;
- int dy = xdev->points.data[i].y - y;
-
- diffs[di] = (byte) dx;
- diffs[di + 1] = (byte) dy;
- uor |= dx | dy;
- sor |= (dx + 0x80) | (dy + 0x80);
- x += dx, y += dy;
- }
- if (!(uor & ~0xff))
- data_type = eUByte;
- else if (!(sor & ~0xff))
- data_type = eSByte;
- else
- break;
- op = pxtLineRelPath;
- /* Use byte values. */
- useb:px_put_np(s, count, data_type);
- spputc(s, op);
- px_put_data_length(s, count * 2); /* 2 bytes per point */
- px_put_bytes(s, diffs, count * 2);
- goto zap;
- case POINTS_CURVES:
- op = pxtBezierPath;
- /* See if we can use byte values. */
- for (i = di = 0; i < count; i += 3, di += 6) {
- int dx1 = xdev->points.data[i].x - x;
- int dy1 = xdev->points.data[i].y - y;
- int dx2 = xdev->points.data[i + 1].x - x;
- int dy2 = xdev->points.data[i + 1].y - y;
- int dx = xdev->points.data[i + 2].x - x;
- int dy = xdev->points.data[i + 2].y - y;
-
- diffs[di] = (byte) dx1;
- diffs[di + 1] = (byte) dy1;
- diffs[di + 2] = (byte) dx2;
- diffs[di + 3] = (byte) dy2;
- diffs[di + 4] = (byte) dx;
- diffs[di + 5] = (byte) dy;
- uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
- sor |= (dx1 + 0x80) | (dy1 + 0x80) |
- (dx2 + 0x80) | (dy2 + 0x80) |
- (dx + 0x80) | (dy + 0x80);
- x += dx, y += dy;
- }
- if (!(uor & ~0xff))
- data_type = eUByte;
- else if (!(sor & ~0xff))
- data_type = eSByte;
- else
- break;
- op = pxtBezierRelPath;
- goto useb;
- default: /* can't happen */
- return_error(gs_error_unknownerror);
- }
- px_put_np(s, count, eSInt16);
- spputc(s, op);
- px_put_data_length(s, count * 4); /* 2 UInt16s per point */
- for (i = 0; i < count; ++i) {
- px_put_s(s, xdev->points.data[i].x);
- px_put_s(s, xdev->points.data[i].y);
- }
- zap:xdev->points.type = POINTS_NONE;
- xdev->points.count = 0;
- }
- return 0;
- }
-
- /* ------ Images ------ */
-
- private image_enum_proc_plane_data(pclxl_image_plane_data);
- private image_enum_proc_end_image(pclxl_image_end_image);
- private const gx_image_enum_procs_t pclxl_image_enum_procs = {
- pclxl_image_plane_data, pclxl_image_end_image
- };
-
- /* Begin an image. */
- private void
- pclxl_write_begin_image(gx_device_pclxl * xdev, uint width, uint height,
- uint dest_width, uint dest_height)
- {
- stream *s = pclxl_stream(xdev);
-
- px_put_usa(s, width, pxaSourceWidth);
- px_put_usa(s, height, pxaSourceHeight);
- px_put_usp(s, dest_width, dest_height);
- px_put_ac(s, pxaDestinationSize, pxtBeginImage);
- }
-
- /* Write rows of an image. */
- /****** IGNORES data_bit ******/
- private void
- pclxl_write_image_data(gx_device_pclxl * xdev, const byte * data, int data_bit,
- uint raster, uint width_bits, int y, int height)
- {
- stream *s = pclxl_stream(xdev);
- uint width_bytes = (width_bits + 7) >> 3;
- uint num_bytes = ROUND_UP(width_bytes, 4) * height;
- bool compress = num_bytes >= 8;
- int i;
-
- px_put_usa(s, y, pxaStartLine);
- px_put_usa(s, height, pxaBlockHeight);
- if (compress) {
- stream_RLE_state rlstate;
- stream_cursor_write w;
- stream_cursor_read r;
-
- /*
- * H-P printers require that all the data for an operator be
- * contained in a single data block. Thus, we must allocate a
- * temporary buffer for the compressed data. Currently we don't go
- * to the trouble of doing two passes if we can't allocate a buffer
- * large enough for the entire transfer.
- */
- byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
- "pclxl_write_image_data");
-
- if (buf == 0)
- goto nc;
- s_RLE_set_defaults_inline(&rlstate);
- rlstate.EndOfData = false;
- s_RLE_init_inline(&rlstate);
- w.ptr = buf - 1;
- w.limit = w.ptr + num_bytes;
- /*
- * If we ever overrun the buffer, it means that the compressed
- * data was larger than the uncompressed. If this happens,
- * write the data uncompressed.
- */
- for (i = 0; i < height; ++i) {
- r.ptr = data + i * raster - 1;
- r.limit = r.ptr + width_bytes;
- if ((*s_RLE_template.process)
- ((stream_state *) & rlstate, &r, &w, false) != 0 ||
- r.ptr != r.limit
- )
- goto ncfree;
- r.ptr = (const byte *)"\000\000\000\000\000";
- r.limit = r.ptr + (-width_bytes & 3);
- if ((*s_RLE_template.process)
- ((stream_state *) & rlstate, &r, &w, false) != 0 ||
- r.ptr != r.limit
- )
- goto ncfree;
- }
- r.ptr = r.limit;
- if ((*s_RLE_template.process)
- ((stream_state *) & rlstate, &r, &w, true) != 0
- )
- goto ncfree;
- {
- uint count = w.ptr + 1 - buf;
-
- px_put_ub(s, eRLECompression);
- px_put_ac(s, pxaCompressMode, pxtReadImage);
- px_put_data_length(s, count);
- px_put_bytes(s, buf, count);
- }
- gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
- return;
- ncfree:gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
- }
- nc:
- /* Write the data uncompressed. */
- px_put_ub(s, eNoCompression);
- px_put_ac(s, pxaCompressMode, pxtReadImage);
- px_put_data_length(s, num_bytes);
- for (i = 0; i < height; ++i) {
- px_put_bytes(s, data + i * raster, width_bytes);
- px_put_bytes(s, (const byte *)"\000\000\000\000", -width_bytes & 3);
- }
- }
-
- /* End an image. */
- private void
- pclxl_write_end_image(gx_device_pclxl * xdev)
- {
- spputc(xdev->strm, pxtEndImage);
- }
-
- /* ------ Fonts ------ */
-
- /* Write a string (single- or double-byte). */
- private void
- px_put_string(stream * s, const byte * data, uint len, bool wide)
- {
- if (wide) {
- spputc(s, pxt_uint16_array);
- px_put_u(s, len);
- px_put_bytes(s, data, len * 2);
- } else {
- spputc(s, pxt_ubyte_array);
- px_put_u(s, len);
- px_put_bytes(s, data, len);
- }
- }
-
- /* Write a 16-bit big-endian value. */
- private void
- px_put_us_be(stream * s, uint i)
- {
- spputc(s, (byte) (i >> 8));
- spputc(s, (byte) i);
- }
-
- /* Define a bitmap font. The client must call px_put_string */
- /* with the font name immediately before calling this procedure. */
- private void
- pclxl_define_bitmap_font(gx_device_pclxl * xdev)
- {
- stream *s = pclxl_stream(xdev);
- static const byte bfh_[] = {
- DA(pxaFontName), DUB(0), DA(pxaFontFormat),
- pxtBeginFontHeader,
- DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
- pxtReadFontHeader,
- pxt_dataLengthByte, 8 + 6 + 4 + 6,
- 0, 0, 0, 0,
- 254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
- 'B', 'R', 0, 0, 0, 4
- };
- static const byte efh_[] = {
- 0xff, 0xff, 0, 0, 0, 0,
- pxtEndFontHeader
- };
-
- PX_PUT_LIT(s, bfh_);
- px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
- px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
- PX_PUT_LIT(s, efh_);
- }
-
- /* Set the font. The client must call px_put_string */
- /* with the font name immediately before calling this procedure. */
- private void
- pclxl_set_font(gx_device_pclxl * xdev)
- {
- stream *s = pclxl_stream(xdev);
- static const byte sf_[] = {
- DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
- pxtSetFont
- };
-
- PX_PUT_LIT(s, sf_);
- }
-
- /* Define a character in a bitmap font. The client must call px_put_string */
- /* with the font name immediately before calling this procedure. */
- private void
- pclxl_define_bitmap_char(gx_device_pclxl * xdev, uint ccode,
- const byte * data, uint raster, uint width_bits, uint height)
- {
- stream *s = pclxl_stream(xdev);
- uint width_bytes = (width_bits + 7) >> 3;
- uint size = 10 + width_bytes * height;
- uint i;
-
- px_put_ac(s, pxaFontName, pxtBeginChar);
- px_put_u(s, ccode);
- px_put_a(s, pxaCharCode);
- if (size > 0xffff) {
- spputc(s, pxt_uint32);
- px_put_l(s, (ulong) size);
- } else
- px_put_us(s, size);
- px_put_ac(s, pxaCharDataSize, pxtReadChar);
- px_put_data_length(s, size);
- px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
- px_put_us_be(s, width_bits);
- px_put_us_be(s, height);
- for (i = 0; i < height; ++i)
- px_put_bytes(s, data + i * raster, width_bytes);
- spputc(s, pxtEndChar);
- }
-
- /* Write the name of the only font we define. */
- private void
- pclxl_write_font_name(gx_device_pclxl * xdev)
- {
- stream *s = pclxl_stream(xdev);
-
- px_put_string(s, (const byte *)"@", 1, false);
- }
-
- /* Look up a bitmap id, return the index in the character table. */
- /* If the id is missing, return an index for inserting. */
- private int
- pclxl_char_index(gx_device_pclxl * xdev, gs_id id)
- {
- int i, i_empty = -1;
- uint ccode;
-
- for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
- i = (i == 0 ? countof(xdev->chars.table) : i) - 1
- ) {
- ccode = xdev->chars.table[i];
- if (ccode == 0)
- return (i_empty >= 0 ? i_empty : i);
- else if (ccode == 1) {
- if (i_empty < 0)
- i_empty = i;
- else if (i == i_empty) /* full table */
- return i;
- } else if (xdev->chars.data[ccode].id == id)
- return i;
- }
- }
-
- /* Remove the character table entry at a given index. */
- private void
- pclxl_remove_char(gx_device_pclxl * xdev, int index)
- {
- uint ccode = xdev->chars.table[index];
- int i;
-
- if (ccode < 2)
- return;
- xdev->chars.count--;
- xdev->chars.used -= xdev->chars.data[ccode].size;
- xdev->chars.table[index] = 1; /* mark as deleted */
- i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
- if (xdev->chars.table[i] == 0) {
- /* The next slot in probe order is empty. */
- /* Mark this slot and any deleted predecessors as empty. */
- for (i = index; xdev->chars.table[i] == 1;
- i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
- )
- xdev->chars.table[i] = 0;
- }
- }
-
- /* Write a bitmap as a text character if possible. */
- /* The caller must set the color, cursor, and RasterOp. */
- /* We know id != gs_no_id. */
- private int
- pclxl_copy_text_char(gx_device_pclxl * xdev, const byte * data,
- int raster, gx_bitmap_id id, int w, int h)
- {
- uint width_bytes = (w + 7) >> 3;
- uint size = width_bytes * h;
- int index;
- uint ccode;
- stream *s = pclxl_stream(xdev);
-
- if (size > MAX_CHAR_SIZE)
- return -1;
- index = pclxl_char_index(xdev, id);
- if ((ccode = xdev->chars.table[index]) < 2) {
- /* Enter the character in the table. */
- while (xdev->chars.used + size > MAX_CHAR_DATA ||
- xdev->chars.count >= MAX_CACHED_CHARS - 2
- ) {
- ccode = xdev->chars.next_out;
- index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
- pclxl_remove_char(xdev, index);
- xdev->chars.next_out =
- (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
- }
- index = pclxl_char_index(xdev, id);
- ccode = xdev->chars.next_in;
- xdev->chars.data[ccode].id = id;
- xdev->chars.data[ccode].size = size;
- xdev->chars.table[index] = ccode;
- xdev->chars.next_in =
- (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
- if (!xdev->chars.count++) {
- /* This is the very first character. */
- pclxl_write_font_name(xdev);
- pclxl_define_bitmap_font(xdev);
- }
- xdev->chars.used += size;
- pclxl_write_font_name(xdev);
- pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
- }
- if (!xdev->font_set) {
- pclxl_write_font_name(xdev);
- pclxl_set_font(xdev);
- xdev->font_set = true;
- } {
- byte cc_bytes[2];
-
- cc_bytes[0] = (byte) ccode;
- cc_bytes[1] = ccode >> 8;
- px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
- }
- px_put_ac(s, pxaTextData, pxtText);
- return 0;
- }
-
- /* ---------------- Vector implementation procedures ---------------- */
-
- private int
- pclxl_beginpage(gx_device_vector * vdev)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
- /*
- * We can't use gdev_vector_stream here, because this may be called
- * from there before in_page is set.
- */
- stream *s = vdev->strm;
-
- px_write_page_header(s, (const gx_device *)vdev);
- px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size);
- spputc(s, pxtBeginPage);
- return 0;
- }
-
- private int
- pclxl_setlinewidth(gx_device_vector * vdev, floatp width)
- {
- stream *s = gdev_vector_stream(vdev);
-
- px_put_us(s, (uint) width);
- px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
- return 0;
- }
-
- private int
- pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
- {
- stream *s = gdev_vector_stream(vdev);
-
- /* The PCL XL cap styles just happen to be identical to PostScript. */
- px_put_ub(s, (byte) cap);
- px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
- return 0;
- }
-
- private int
- pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
- {
- stream *s = gdev_vector_stream(vdev);
-
- /* The PCL XL join styles just happen to be identical to PostScript. */
- px_put_ub(s, (byte) join);
- px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
- return 0;
- }
-
- private int
- pclxl_setmiterlimit(gx_device_vector * vdev, floatp limit)
- {
- stream *s = gdev_vector_stream(vdev);
- /*
- * Amazingly enough, the PCL XL specification doesn't allow real
- * numbers for the miter limit.
- */
- int i_limit = (int)(limit + 0.5);
-
- px_put_u(s, max(i_limit, 1));
- px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
- return 0;
- }
-
- private int
- pclxl_setdash(gx_device_vector * vdev, const float *pattern, uint count,
- floatp offset)
- {
- stream *s = gdev_vector_stream(vdev);
-
- if (count == 0) {
- static const byte nac_[] = {
- DUB(0), DA(pxaSolidLine)
- };
-
- PX_PUT_LIT(s, nac_);
- } else if (count > 255)
- return_error(gs_error_limitcheck);
- else {
- uint i;
-
- /*
- * Astoundingly, PCL XL doesn't allow real numbers here.
- * Do the best we can.
- */
- spputc(s, pxt_uint16_array);
- px_put_ub(s, count);
- for (i = 0; i < count; ++i)
- px_put_s(s, (uint)pattern[i]);
- px_put_a(s, pxaLineDashStyle);
- if (offset != 0) {
- px_put_rl(s, offset);
- px_put_a(s, pxaDashOffset);
- }
- }
- spputc(s, pxtSetLineDash);
- return 0;
- }
-
- private int
- pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
- gs_logical_operation_t diff)
- {
- stream *s = gdev_vector_stream(vdev);
-
- if (diff & lop_S_transparent) {
- px_put_ub(s, (lop & lop_S_transparent ? 1 : 0));
- px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
- }
- if (diff & lop_T_transparent) {
- px_put_ub(s, (lop & lop_T_transparent ? 1 : 0));
- px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
- }
- if (lop_rop(diff)) {
- px_put_ub(s, lop_rop(lop));
- px_put_ac(s, pxaROP3, pxtSetROP);
- }
- return 0;
- }
-
- private int
- pclxl_setfillcolor(gx_device_vector * vdev, const gx_drawing_color * pdc)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
-
- return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
- }
-
- private int
- pclxl_setstrokecolor(gx_device_vector * vdev, const gx_drawing_color * pdc)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
-
- return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
- }
-
- private int
- pclxl_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
- fixed y1, gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
- stream *s = gdev_vector_stream(vdev);
-
- /* Check for out-of-range points. */
- #define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
- if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
- OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
- )
- return_error(gs_error_rangecheck);
- #undef OUT_OF_RANGE
- if (type & (gx_path_type_fill | gx_path_type_stroke)) {
- pclxl_set_paints(xdev, type);
- px_put_usq_fixed(s, x0, y0, x1, y1);
- px_put_ac(s, pxaBoundingBox, pxtRectangle);
- }
- if (type & gx_path_type_clip) {
- static const byte cr_[] = {
- DA(pxaBoundingBox),
- DUB(eInterior), DA(pxaClipRegion),
- pxtSetClipRectangle
- };
-
- px_put_usq_fixed(s, x0, y0, x1, y1);
- PX_PUT_LIT(s, cr_);
- }
- return 0;
- }
-
- private int
- pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
- stream *s = gdev_vector_stream(vdev);
-
- spputc(s, pxtNewPath);
- xdev->points.type = POINTS_NONE;
- xdev->points.count = 0;
- return 0;
- }
-
- private int
- pclxl_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
- gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
- int code = pclxl_flush_points(xdev);
-
- if (code < 0)
- return code;
- return pclxl_set_cursor(xdev,
- xdev->points.current.x = (int)x,
- xdev->points.current.y = (int)y);
- }
-
- private int
- pclxl_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
- gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
-
- if (xdev->points.type != POINTS_LINES ||
- xdev->points.count >= NUM_POINTS
- ) {
- if (xdev->points.type != POINTS_NONE) {
- int code = pclxl_flush_points(xdev);
-
- if (code < 0)
- return code;
- }
- xdev->points.current.x = (int)x0;
- xdev->points.current.y = (int)y0;
- xdev->points.type = POINTS_LINES;
- } {
- gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
-
- ppt->x = (int)x, ppt->y = (int)y;
- }
- return 0;
- }
-
- private int
- pclxl_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
- floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3,
- gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
-
- if (xdev->points.type != POINTS_CURVES ||
- xdev->points.count >= NUM_POINTS - 2
- ) {
- if (xdev->points.type != POINTS_NONE) {
- int code = pclxl_flush_points(xdev);
-
- if (code < 0)
- return code;
- }
- xdev->points.current.x = (int)x0;
- xdev->points.current.y = (int)y0;
- xdev->points.type = POINTS_CURVES;
- }
- {
- gs_int_point *ppt = &xdev->points.data[xdev->points.count];
-
- ppt->x = (int)x1, ppt->y = (int)y1, ++ppt;
- ppt->x = (int)x2, ppt->y = (int)y2, ++ppt;
- ppt->x = (int)x3, ppt->y = (int)y3;
- }
- xdev->points.count += 3;
- return 0;
- }
-
- private int
- pclxl_closepath(gx_device_vector * vdev, floatp x, floatp y,
- floatp x_start, floatp y_start, gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
- stream *s = gdev_vector_stream(vdev);
- int code = pclxl_flush_points(xdev);
-
- if (code < 0)
- return code;
- spputc(s, pxtCloseSubPath);
- xdev->points.current.x = (int)x_start;
- xdev->points.current.y = (int)y_start;
- return 0;
- }
-
- private int
- pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
- stream *s = gdev_vector_stream(vdev);
- int code = pclxl_flush_points(xdev);
- gx_path_type_t rule = type & gx_path_type_rule;
-
- if (code < 0)
- return code;
- if (type & (gx_path_type_fill | gx_path_type_stroke)) {
- pclxl_set_paints(xdev, type);
- spputc(s, pxtPaintPath);
- }
- if (type & gx_path_type_clip) {
- static const byte scr_[] = {
- DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
- };
-
- if (rule != xdev->clip_rule) {
- px_put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
- eNonZeroWinding));
- px_put_ac(s, pxaClipMode, pxtSetClipMode);
- xdev->clip_rule = rule;
- }
- PX_PUT_LIT(s, scr_);
- }
- return 0;
- }
-
- /* Vector implementation procedures */
-
- private const gx_device_vector_procs pclxl_vector_procs = {
- /* Page management */
- pclxl_beginpage,
- /* Imager state */
- pclxl_setlinewidth,
- pclxl_setlinecap,
- pclxl_setlinejoin,
- pclxl_setmiterlimit,
- pclxl_setdash,
- gdev_vector_setflat,
- pclxl_setlogop,
- /* Other state */
- pclxl_setfillcolor,
- pclxl_setstrokecolor,
- /* Paths */
- gdev_vector_dopath,
- pclxl_dorect,
- pclxl_beginpath,
- pclxl_moveto,
- pclxl_lineto,
- pclxl_curveto,
- pclxl_closepath,
- pclxl_endpath
- };
-
- /* ---------------- Driver procedures ---------------- */
-
- /* ------ Open/close/page ------ */
-
- /* Open the device. */
- private int
- pclxl_open_device(gx_device * dev)
- {
- gx_device_vector *const vdev = (gx_device_vector *)dev;
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- int code;
-
- vdev->v_memory = dev->memory;
- /****** WRONG ******/
- vdev->vec_procs = &pclxl_vector_procs;
- code = gdev_vector_open_file(vdev, 512);
- if (code < 0)
- return code;
- pclxl_page_init(xdev);
- px_write_file_header(vdev->strm, dev);
- xdev->media_size = pxeMediaSize_next; /* no size selected */
- memset(&xdev->chars, 0, sizeof(xdev->chars));
- xdev->chars.next_in = xdev->chars.next_out = 2;
- return 0;
- }
-
- /* Wrap up ("output") a page. */
- /* We only support flush = true, and we don't support num_copies != 1. */
- private int
- pclxl_output_page(gx_device * dev, int num_copies, int flush)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- stream *s;
-
- /* Note that unlike close_device, end_page must not omit blank pages. */
- if (!xdev->in_page)
- pclxl_beginpage((gx_device_vector *)dev);
- s = xdev->strm;
- spputc(s, pxtEndPage);
- sflush(s);
- pclxl_page_init(xdev);
- if (ferror(xdev->file))
- return_error(gs_error_ioerror);
- return gx_finish_output_page(dev, num_copies, flush);
- }
-
- /* Close the device. */
- /* Note that if this is being called as a result of finalization, */
- /* the stream may no longer exist. */
- private int
- pclxl_close_device(gx_device * dev)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- FILE *file = xdev->file;
-
- if (xdev->in_page)
- fputc(pxtEndPage, file);
- px_write_file_trailer(file);
- return gdev_vector_close_file((gx_device_vector *)dev);
- }
-
- /* ------ One-for-one images ------ */
-
- private const byte eBit_values[] = {
- 0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
- };
-
- /* Copy a monochrome bitmap. */
- private int
- pclxl_copy_mono(gx_device * dev, const byte * data, int data_x, int raster,
- gx_bitmap_id id, int x, int y, int w, int h,
- gx_color_index zero, gx_color_index one)
- {
- gx_device_vector *const vdev = (gx_device_vector *)dev;
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- int code;
- stream *s;
- gx_color_index color0 = zero, color1 = one;
- gs_logical_operation_t lop;
- byte palette[2 * 3];
- int palette_size;
- pxeColorSpace_t color_space;
-
- fit_copy(dev, data, data_x, raster, id, x, y, w, h);
- code = gdev_vector_update_clip_path(vdev, NULL);
- if (code < 0)
- return code;
- pclxl_set_cursor(xdev, x, y);
- if (id != gs_no_id && zero == gx_no_color_index &&
- one != gx_no_color_index && data_x == 0
- ) {
- gx_drawing_color dcolor;
-
- color_set_pure(&dcolor, one);
- pclxl_setfillcolor(vdev, &dcolor);
- if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
- return 0;
- }
- /*
- * The following doesn't work if we're writing white with a mask.
- * We'll fix it eventually.
- */
- if (zero == gx_no_color_index) {
- if (one == gx_no_color_index)
- return 0;
- lop = rop3_S | lop_S_transparent;
- color0 = (1 << dev->color_info.depth) - 1;
- } else if (one == gx_no_color_index) {
- lop = rop3_S | lop_S_transparent;
- color1 = (1 << dev->color_info.depth) - 1;
- } else {
- lop = rop3_S;
- }
- if (dev->color_info.num_components == 1 ||
- (RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
- ) {
- palette[0] = (byte) color0;
- palette[1] = (byte) color1;
- palette_size = 2;
- color_space = eGray;
- } else {
- palette[0] = (byte) (color0 >> 16);
- palette[1] = (byte) (color0 >> 8);
- palette[2] = (byte) color0;
- palette[3] = (byte) (color1 >> 16);
- palette[4] = (byte) (color1 >> 8);
- palette[5] = (byte) color1;
- palette_size = 6;
- color_space = eRGB;
- }
- code = gdev_vector_update_log_op(vdev, lop);
- if (code < 0)
- return 0;
- pclxl_set_color_palette(xdev, color_space, palette, palette_size);
- s = pclxl_stream(xdev);
- {
- static const byte mi_[] = {
- DUB(e1Bit), DA(pxaColorDepth),
- DUB(eIndexedPixel), DA(pxaColorMapping)
- };
-
- PX_PUT_LIT(s, mi_);
- }
- pclxl_write_begin_image(xdev, w, h, w, h);
- pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
- pclxl_write_end_image(xdev);
- return 0;
- }
-
- /* Copy a color bitmap. */
- private int
- pclxl_copy_color(gx_device * dev,
- const byte * base, int sourcex, int raster, gx_bitmap_id id,
- int x, int y, int w, int h)
- {
- gx_device_vector *const vdev = (gx_device_vector *)dev;
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- stream *s;
- uint source_bit;
- int code;
-
- fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
- code = gdev_vector_update_clip_path(vdev, NULL);
- if (code < 0)
- return code;
- source_bit = sourcex * dev->color_info.depth;
- if ((source_bit & 7) != 0)
- return gx_default_copy_color(dev, base, sourcex, raster, id,
- x, y, w, h);
- gdev_vector_update_log_op(vdev, rop3_S);
- pclxl_set_cursor(xdev, x, y);
- s = pclxl_stream(xdev);
- {
- static const byte ci_[] = {
- DA(pxaColorDepth),
- DUB(eDirectPixel), DA(pxaColorMapping)
- };
-
- px_put_ub(s, eBit_values[dev->color_info.depth /
- dev->color_info.num_components]);
- PX_PUT_LIT(s, ci_);
- }
- pclxl_write_begin_image(xdev, w, h, w, h);
- pclxl_write_image_data(xdev, base, source_bit, raster,
- w * dev->color_info.depth, 0, h);
- pclxl_write_end_image(xdev);
- return 0;
- }
-
- /* Fill a mask. */
- private int
- pclxl_fill_mask(gx_device * dev,
- const byte * data, int data_x, int raster, gx_bitmap_id id,
- int x, int y, int w, int h,
- const gx_drawing_color * pdcolor, int depth,
- gs_logical_operation_t lop, const gx_clip_path * pcpath)
- {
- gx_device_vector *const vdev = (gx_device_vector *)dev;
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- int code;
- stream *s;
-
- fit_copy(dev, data, data_x, raster, id, x, y, w, h);
- if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1)
- return gx_default_fill_mask(dev, data, data_x, raster, id,
- x, y, w, h, pdcolor, depth,
- lop, pcpath);
- code = gdev_vector_update_clip_path(vdev, pcpath);
- if (code < 0)
- return code;
- code = gdev_vector_update_fill_color(vdev, pdcolor);
- if (code < 0)
- return 0;
- pclxl_set_cursor(xdev, x, y);
- if (id != gs_no_id && data_x == 0) {
- code = gdev_vector_update_log_op(vdev, lop);
- if (code < 0)
- return 0;
- if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
- return 0;
- }
- code = gdev_vector_update_log_op(vdev,
- lop | rop3_S | lop_S_transparent);
- if (code < 0)
- return 0;
- pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
- s = pclxl_stream(xdev);
- {
- static const byte mi_[] = {
- DUB(e1Bit), DA(pxaColorDepth),
- DUB(eIndexedPixel), DA(pxaColorMapping)
- };
-
- PX_PUT_LIT(s, mi_);
- }
- pclxl_write_begin_image(xdev, w, h, w, h);
- pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
- pclxl_write_end_image(xdev);
- return 0;
- }
-
- /* Do a RasterOp. */
- private int
- pclxl_strip_copy_rop(gx_device * dev, const byte * sdata, int sourcex,
- uint sraster, gx_bitmap_id id,
- const gx_color_index * scolors,
- const gx_strip_bitmap * textures,
- const gx_color_index * tcolors,
- int x, int y, int width, int height,
- int phase_x, int phase_y, gs_logical_operation_t lop)
- { /* We can't do general RasterOps yet. */
- /****** WORK IN PROGRESS ******/
- return 0;
- }
-
- /* ------ High-level images ------ */
-
- #define MAX_ROW_DATA 4000 /* arbitrary */
- typedef struct pclxl_image_enum_s {
- gdev_vector_image_enum_common;
- gs_matrix mat;
- struct ir_ {
- byte *data;
- int num_rows; /* # of allocated rows */
- int first_y;
- uint raster;
- } rows;
- } pclxl_image_enum_t;
- gs_private_st_suffix_add1(st_pclxl_image_enum, pclxl_image_enum_t,
- "pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
- pclxl_image_enum_reloc_ptrs, st_vector_image_enum,
- rows.data);
-
- /* Start processing an image. */
- private int
- pclxl_begin_image(gx_device * dev,
- const gs_imager_state * pis, const gs_image_t * pim,
- gs_image_format_t format, const gs_int_rect * prect,
- const gx_drawing_color * pdcolor,
- const gx_clip_path * pcpath, gs_memory_t * mem,
- gx_image_enum_common_t ** pinfo)
- {
- gx_device_vector *const vdev = (gx_device_vector *)dev;
- gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
- const gs_color_space *pcs = pim->ColorSpace;
- pclxl_image_enum_t *pie;
- byte *row_data;
- int num_rows;
- uint row_raster;
- /*
- * Following should divide by num_planes, but we only handle chunky
- * images, i.e., num_planes = 1.
- */
- int bits_per_pixel =
- (pim->ImageMask ? 1 :
- pim->BitsPerComponent * gs_color_space_num_components(pcs));
- gs_matrix mat;
- int code;
-
- /*
- * Check whether we can handle this image. PCL XL 1.0 and 2.0 only
- * handle orthogonal transformations.
- */
- gs_matrix_invert(&pim->ImageMatrix, &mat);
- gs_matrix_multiply(&mat, &ctm_only(pis), &mat);
- /* Currently we only handle portrait transformations. */
- if (mat.xx <= 0 || mat.xy != 0 || mat.yx != 0 || mat.yy <= 0 ||
- (pim->ImageMask ?
- (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
- (!pclxl_can_handle_color_space(pim->ColorSpace) ||
- (bits_per_pixel != 1 && bits_per_pixel != 4 &&
- bits_per_pixel != 8))) ||
- format != gs_image_format_chunky ||
- prect
- )
- goto use_default;
- row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
- num_rows = MAX_ROW_DATA / row_raster;
- if (num_rows > pim->Height)
- num_rows = pim->Height;
- if (num_rows <= 0)
- num_rows = 1;
- pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
- "pclxl_begin_image");
- row_data = gs_alloc_bytes(mem, num_rows * row_raster,
- "pclxl_begin_image(rows)");
- if (pie == 0 || row_data == 0) {
- code = gs_note_error(gs_error_VMerror);
- goto fail;
- }
- code = gdev_vector_begin_image(vdev, pis, pim, format, prect,
- pdcolor, pcpath, mem,
- &pclxl_image_enum_procs,
- (gdev_vector_image_enum_t *)pie);
- if (code < 0)
- return code;
- pie->mat = mat;
- pie->rows.data = row_data;
- pie->rows.num_rows = num_rows;
- pie->rows.first_y = 0;
- pie->rows.raster = row_raster;
- *pinfo = (gx_image_enum_common_t *) pie;
- {
- gs_logical_operation_t lop = pis->log_op;
-
- if (pim->ImageMask) {
- const byte *palette = (const byte *)
- (pim->Decode[0] ? "\377\000" : "\000\377");
-
- code = gdev_vector_update_fill_color(vdev, pdcolor);
- if (code < 0)
- goto fail;
- code = gdev_vector_update_log_op
- (vdev, lop | rop3_S | lop_S_transparent);
- if (code < 0)
- goto fail;
- pclxl_set_color_palette(xdev, eGray, palette, 2);
- } else {
- int bpc = pim->BitsPerComponent;
- int num_components = pie->plane_depths[0] * pie->num_planes / bpc;
- int sample_max = (1 << bpc) - 1;
- byte palette[256 * 3];
- int i;
-
- code = gdev_vector_update_log_op
- (vdev, (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
- if (code < 0)
- goto fail;
- for (i = 0; i < 1 << bits_per_pixel; ++i) {
- gs_client_color cc;
- gx_device_color devc;
- int cv = i, j;
- gx_color_index ci;
-
- for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
- cc.paint.values[j] = pim->Decode[j * 2] +
- (cv & sample_max) *
- (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
- sample_max;
- (*pcs->type->remap_color)
- (&cc, pcs, &devc, pis, dev, gs_color_select_source);
- if (!gx_dc_is_pure(&devc))
- return_error(gs_error_Fatal);
- ci = gx_dc_pure_color(&devc);
- if (dev->color_info.num_components == 1) {
- palette[i] = (byte)ci;
- } else {
- byte *ppal = &palette[i * 3];
-
- ppal[0] = (byte) (ci >> 16);
- ppal[1] = (byte) (ci >> 8);
- ppal[2] = (byte) ci;
- }
- }
- if (dev->color_info.num_components == 1)
- pclxl_set_color_palette(xdev, eGray, palette,
- 1 << bits_per_pixel);
- else
- pclxl_set_color_palette(xdev, eRGB, palette,
- 3 << bits_per_pixel);
- }
- }
- return 0;
- fail:
- gs_free_object(mem, row_data, "pclxl_begin_image(rows)");
- gs_free_object(mem, pie, "pclxl_begin_image");
- use_default:
- return gx_default_begin_image(dev, pis, pim, format, prect,
- pdcolor, pcpath, mem, pinfo);
- }
-
- /* Write one strip of an image, from pie->rows.first_y to pie->y. */
- private int
- image_transform_x(const pclxl_image_enum_t *pie, int sx)
- {
- return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
- ((const gx_device_pclxl *)pie->dev)->scale.x);
- }
- private int
- image_transform_y(const pclxl_image_enum_t *pie, int sy)
- {
- return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
- ((const gx_device_pclxl *)pie->dev)->scale.y);
- }
- private int
- pclxl_image_write_rows(pclxl_image_enum_t *pie)
- {
- gx_device_pclxl *const xdev = (gx_device_pclxl *)pie->dev;
- stream *s = pclxl_stream(xdev);
- int y = pie->rows.first_y;
- int h = pie->y - y;
- int xo = image_transform_x(pie, 0);
- int yo = image_transform_y(pie, y);
- int dw = image_transform_x(pie, pie->width) - xo;
- int dh = image_transform_y(pie, y + h) - yo;
- static const byte ii_[] = {
- DA(pxaColorDepth),
- DUB(eIndexedPixel), DA(pxaColorMapping)
- };
-
- if (dw <= 0 || dh <= 0)
- return 0;
- pclxl_set_cursor(xdev, xo, yo);
- px_put_ub(s, eBit_values[pie->bits_per_pixel]);
- PX_PUT_LIT(s, ii_);
- pclxl_write_begin_image(xdev, pie->width, h, dw, dh);
- pclxl_write_image_data(xdev, pie->rows.data, 0, pie->rows.raster,
- pie->rows.raster << 3, 0, h);
- pclxl_write_end_image(xdev);
- return 0;
- }
-
- /* Process the next piece of an image. */
- private int
- pclxl_image_plane_data(gx_image_enum_common_t * info,
- const gx_image_plane_t * planes, int height,
- int *rows_used)
- {
- pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
- int data_bit = planes[0].data_x * info->plane_depths[0];
- int width_bits = pie->width * info->plane_depths[0];
- int i;
-
- /****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
- if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
- return_error(gs_error_rangecheck);
- if (height > pie->height - pie->y)
- height = pie->height - pie->y;
- for (i = 0; i < height; pie->y++, ++i) {
- if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
- int code = pclxl_image_write_rows(pie);
-
- if (code < 0)
- return code;
- pie->rows.first_y = pie->y;
- }
- memcpy(pie->rows.data +
- pie->rows.raster * (pie->y - pie->rows.first_y),
- planes[0].data + planes[0].raster * i + (data_bit >> 3),
- pie->rows.raster);
- }
- *rows_used = height;
- return pie->y >= pie->height;
- }
-
- /* Clean up by releasing the buffers. */
- private int
- pclxl_image_end_image(gx_image_enum_common_t * info, bool draw_last)
- {
- pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
- int code = 0;
-
- /* Write the final strip, if any. */
- if (pie->y > pie->rows.first_y && draw_last)
- code = pclxl_image_write_rows(pie);
- gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
- gs_free_object(pie->memory, pie, "pclxl_end_image");
- return code;
- }
-